package org.finesys.common.es.config;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.finesys.common.es.pool.ElasticsearchAsyncClientFactory;
import org.finesys.common.es.pool.ElasticsearchAsyncClientPool;
import org.finesys.common.es.properties.MyElasticsearchProperties;
import org.jasypt.encryption.StringEncryptor;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;

import co.elastic.clients.elasticsearch.ElasticsearchAsyncClient;
import co.elastic.clients.json.JsonpMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@AutoConfiguration
@EnableConfigurationProperties(MyElasticsearchProperties.class)
@RequiredArgsConstructor
@Slf4j
@ConditionalOnProperty(name = "fine.elasticsearch.enableAsyncPool", havingValue = "true")
public class ElasticsearchAsyncClientPoolConfig {
    //配置类
    private final MyElasticsearchProperties elasticsearchProperties;

    //加密工具类
    private final StringEncryptor stringEncryptor;


    @Bean
    public ElasticsearchAsyncClientFactory elasticsearchAsyncClientFactory(JsonpMapper jsonpMapper) {
        return new ElasticsearchAsyncClientFactory(elasticsearchProperties, jsonpMapper, stringEncryptor);
    }

    /**
     * 池化处理
     */
    @Bean
    public ElasticsearchAsyncClientPool elasticsearchAsyncClientPool(ElasticsearchAsyncClientFactory elasticsearchAsyncClientFactory) {
        GenericObjectPoolConfig<ElasticsearchAsyncClient> genericObjectPoolConfig = genericObjectPoolConfig();
        ElasticsearchAsyncClientPool elasticsearchAsyncClientPool = new ElasticsearchAsyncClientPool(elasticsearchAsyncClientFactory, genericObjectPoolConfig);
        //初始化连接池
        try {
            elasticsearchAsyncClientPool.preparePool();
        } catch (Exception e) {
            if (log.isInfoEnabled()) {
                log.error("初始化连接池失败", e);
            }
        }
        return elasticsearchAsyncClientPool;
    }

    /**
     * 创建并配置一个GenericObjectPoolConfig<ElasticsearchAsyncClient>实例。
     *
     * <p>此方法创建一个新的GenericObjectPoolConfig实例，并根据Elasticsearch的配置属性对其进行配置。
     * 这些配置包括最大总对象数、最大空闲对象数、最小空闲对象数、最大等待时间、最小可驱逐空闲时间、
     * 驱逐器关闭超时时间和软最小可驱逐空闲时间。
     *
     * @return 配置好的GenericObjectPoolConfig<ElasticsearchAsyncClient>实例。
     */
    private GenericObjectPoolConfig<ElasticsearchAsyncClient> genericObjectPoolConfig() {
        GenericObjectPoolConfig<ElasticsearchAsyncClient> config = new GenericObjectPoolConfig<>();
        config.setMaxTotal(elasticsearchProperties.getMaxTotal());
        config.setMaxIdle(elasticsearchProperties.getMaxIdle());
        config.setMinIdle(elasticsearchProperties.getMinIdle());
        config.setMaxWait(elasticsearchProperties.getMaxWaitDuration());
        config.setMinEvictableIdleTime(elasticsearchProperties.getMinEvictableIdleDuration());
        config.setEvictorShutdownTimeout(elasticsearchProperties.getEvictorShutdownTimeoutDuration());
        config.setSoftMinEvictableIdleTime(elasticsearchProperties.getSoftMinEvictableIdleDuration());
        config.setTestOnBorrow(elasticsearchProperties.isTestOnBorrow());
        config.setTestOnReturn(elasticsearchProperties.isTestOnReturn());
        config.setTestWhileIdle(elasticsearchProperties.isTestWhileIdle());
        config.setTimeBetweenEvictionRuns(elasticsearchProperties.getTimeBetweenEvictionRuns());
        config.setNumTestsPerEvictionRun(elasticsearchProperties.getNumTestsPerEvictionRun());
        config.setBlockWhenExhausted(elasticsearchProperties.isBlockWhenExhausted());
        config.setLifo(elasticsearchProperties.isLifo());
        return config;
    }
}
